package com.skyline.courier.net.provider.netty;

import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleStateEvent;

import java.net.SocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.skyline.courier.net.Connection;
import com.skyline.courier.net.ConnectionManager;
import com.skyline.courier.net.Heartbeat;
import com.skyline.courier.net.Statistic;

public class StateManagerChannelHandler extends ChannelDuplexHandler {
	private static final Logger LOGGER = LoggerFactory.getLogger(StateManagerChannelHandler.class);
	private Statistic statistic;
	private ConnectionManager connectionManager;

	public StateManagerChannelHandler(Statistic statistic,  ConnectionManager connectionManager) {
		this.statistic = statistic;
		this.connectionManager = connectionManager;
	}
	
	public void setStatistic(Statistic statistic) {
		this.statistic = statistic;
	}
	
	public void setConnectionManager(ConnectionManager connectionManager) {
		this.connectionManager = connectionManager;
	}
	
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent e = (IdleStateEvent) evt;
			Channel channel = ctx.channel();
			SocketAddress address = channel.remoteAddress();
			
			if (e == IdleStateEvent.READER_IDLE_STATE_EVENT) {
				LOGGER.error("连接读超时，即将关闭超时channel[" + channel.toString() + "]");

				ctx.close();
				
				disconnectAddress(address);
				
			} else if (e == IdleStateEvent.WRITER_IDLE_STATE_EVENT) {
				if (channel.isActive()) {
					channel.writeAndFlush(Heartbeat.getHeartbeat());
					sentHeartbeat(address);
				} else {
					LOGGER.error("连接写超时，超时channel[" + channel + "]，channel未激活");
				}
			}
		}

		super.userEventTriggered(ctx, evt);
	}
	
	private void disconnectAddress(SocketAddress address) {
		if(connectionManager != null) {
			Connection connection = connectionManager.removeConnected(address);
			if(connection != null) {
				connectionManager.addDisconnectAddress(address, connection);
			}
		}
	}
	
	private void sentHeartbeat(SocketAddress address) {
		long now = System.currentTimeMillis();
		statistic.sentHeartBeat(address, now);
	}
	
	private void receivedHeartbeat(SocketAddress address) {
		long now = System.currentTimeMillis();
		statistic.receivedHeartBeat(address, now);
	}
	

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		if (msg == Heartbeat.getHeartbeat()) {
			receivedHeartbeat(ctx.channel().remoteAddress());
			return;
		}
		super.channelRead(ctx, msg);
	}
	
}
